package org.delphy.crimson
{
	import caurina.transitions.Tweener;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	
	import mx.containers.Canvas;
	import mx.core.Application;
	import mx.managers.PopUpManager;
	
	public class CrimsonRingMenu extends Canvas
	{
		public var transitionTime:Number=2;
		protected var opened:Boolean=false;
		protected var closing:Boolean=false;

		protected var _host:DisplayObject=null;		
		public function get host():DisplayObject
		{ 
			return _host; 
		}		
		public function set host(value:DisplayObject):void
		{
			if (value !== _host)
			{
				_host = value;
			}
		}
		
		protected var curtain:CrimsonCurtain;
		protected var spot:CrimsonSpot;
		
		public function CrimsonRingMenu()
		{
			super();
			
			horizontalScrollPolicy="off";
			verticalScrollPolicy="off";	
			
			clipContent = false;
			
			// We are creating a rawChild in the constructor. This is definitely not a natural way,
			// but it helps because addChild() will be executed before createChildren(), which is the normal
			// place to put these code. Add the bgCurtain in the constructor will ensure it does not appear on the top
			curtain=new CrimsonCurtain();		
			curtain.addEventListener(MouseEvent.CLICK, close);
			
			addEventListener(MouseEvent.CLICK, close);
			
			// Hack: pre-create the curtain and the spot. Other the first time they get created, there will be no animation effects
			// This is used as a cache
			PopUpManager.addPopUp(curtain, DisplayObject(Application.application), false);
			PopUpManager.removePopUp(curtain);
			
			spot = new CrimsonSpot();
			spot.alpha = 0;
			PopUpManager.addPopUp(spot, DisplayObject(Application.application), false);
			PopUpManager.removePopUp(spot);
			
		}
		
		public function popUp():void{
			if(opened)
				return;
				
			if(_host==null)
				_host=parent;

			// Popup the curtain
			curtain.popUp();
			
			for(var i:uint=0;i<numChildren;i++){
				var child:DisplayObject=getChildAt(i);
				child.x=width/2;
				child.y=height/2;
				child.alpha=0;
				
				child.addEventListener(MouseEvent.CLICK,close);
			}
			
			var hostCenter:Point=new Point(_host.x,_host.y);
			hostCenter=_host.parent.localToGlobal(hostCenter);
			
			if(hostCenter.y + height > Application.application.height)
				hostCenter.y = Application.application.height - height;

			if(hostCenter.x + width > Application.application.width)
				hostCenter.x = Application.application.width - width;
			
			x=hostCenter.x+_host.width/2-width/2;
			y=hostCenter.y+_host.height/2-height/2;
			
			// Popup the spot
			PopUpManager.addPopUp(spot, DisplayObject(Application.application), false);
			spot.x = hostCenter.x - spot.width / 2 + _host.width / 2;
			spot.y = hostCenter.y - spot.height / 2 + _host.height / 2;
			Tweener.addTween(spot, {alpha: 1, time:transitionTime});
			
			// Remove from the parent container to avoid ending up with an exception
			if(parent)
				parent.removeChild(this);
						
			PopUpManager.addPopUp(this, DisplayObject(Application.application), false);
			arrangeChildren();

			opened=true;
		}
				
		protected function arrangeChildren():void{
			for(var i:uint=0;i<numChildren;i++){
				var angle:Number=-Math.PI + Math.PI*2/numChildren*i;
				var childPosition:Point=getPointAt(angle);
				var child:DisplayObject=getChildAt(i);
				
				childPosition.x=childPosition.x-child.width;
				if(childPosition.x<0)
					childPosition.x=0;
				else if(childPosition.x+child.width>width)
					childPosition.x=width-child.width;
				

				childPosition.y=childPosition.y-child.height;
				if(childPosition.y<0)
					childPosition.y=0;
				else if(childPosition.y+child.height>height)
					childPosition.y=height-child.height;
				
				Tweener.addTween(child,{x: childPosition.x,
										y: childPosition.y,
										alpha: 1,
										time: transitionTime});
			}
		}
		
		override public function addChild(child:DisplayObject):DisplayObject{
			child.alpha = 0;
			return super.addChild(child);
		}
		
		protected function getPointAt(angle:Number):Point{
			var pt:Point=new Point();
			pt.x=width/2 * Math.cos(angle)+width/2;
			pt.y=height/2 * Math.sin(angle)+height/2;
			
			return pt;
		}
		
		public function close(evt:Event=null):void{
			if(!closing)
				closing=true;
			else
				return;

			curtain.close();
			Tweener.addTween(spot, {alpha: 0, time:transitionTime});
			for (var i:uint=0;i<numChildren;i++){
				var child:DisplayObject=getChildAt(i);
				Tweener.addTween(child,{x:width/2,
										y:height/2,
										alpha: 0,
										time:transitionTime});
			}			
			
			var timer:Timer=new Timer(transitionTime*1000, 0);
			timer.start();
			timer.addEventListener(TimerEvent.TIMER, closePopUp);
		}
		
		/**
		 * @protected
		 */
		protected function closePopUp(evt:TimerEvent):void{
			// This seems to be a new bug in Flex 4 beta? We have to manually stop the timer,
			// or it will emits TimerEvent forever
			Timer(evt.target).stop();
			PopUpManager.removePopUp(this);
			PopUpManager.removePopUp(spot);
			
			opened=false;
			closing=false;
		}		
	}
}